package com.zzh.lib.recorder.utils;


import android.media.AudioFormat;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * Created by zzh on 2024/12/17.
 *
 * @date: 2024/12/17 17:59
 * @email: zzh_hz@126.com
 * @author: zzh
 * @description: com.zzh.lib.recorder.utils
 */
public class PcmHeader {
    private static final int HEADER_SIZE = 44; // WAV header size

    private PcmHeader() {
    }

    public static void saveWaveDelayTotalLength(BufferedOutputStream os, int sampleRate, int channelConfig, long audioFormat) {
        if (os == null) {
            return;
        }

        int channels = channelConfig == AudioFormat.CHANNEL_IN_MONO ? 1 : 2;
        short bitsPerSample = (short) (audioFormat == AudioFormat.ENCODING_PCM_16BIT ? 16 : 8);

        long totalAudioLen = 0;
        long totalDataLen = totalAudioLen + 36;
        long byteRate = (long) sampleRate * channels * bitsPerSample / 8;

        ByteBuffer header = ByteBuffer.allocate(44);
        header.order(ByteOrder.LITTLE_ENDIAN);

        header.putInt(0x46464952); // "RIFF"
        header.putInt((int) totalDataLen);
        header.putInt(0x45564157); // "WAVE"

        header.putInt(0x20746D66); // "fmt "
        header.putInt(16); // PCM format chunk size
        header.putShort((short) 1); // PCM format tag
        header.putShort((short) channels);
        header.putInt(sampleRate);
        header.putInt((int) byteRate);
        header.putShort((short) ((channels * bitsPerSample) / 8));
        header.putShort(bitsPerSample);

        header.putInt(0x61746164); // "data"
        header.putInt((int) totalAudioLen);

        try {
            os.write(header.array());
        } catch (IOException e) {
            HLog.isMRLogE(e.getLocalizedMessage());
        }
    }

    public void saveWaveHeader(File fd, int sampleRate, int channelConfig, long audioFormat) {
        try {

            RandomAccessFile raf = new RandomAccessFile(fd, "rw");
            raf.seek(0); // Total Length
            int channels = channelConfig == AudioFormat.CHANNEL_IN_MONO ? 1 : 2;
            short bitsPerSample = (short) (audioFormat == AudioFormat.ENCODING_PCM_16BIT ? 16 : 8);


            long totalAudioLen = fd.length();
            long totalDataLen = totalAudioLen + 36;
            long byteRate = (long) sampleRate * channels * bitsPerSample / 8;

            ByteBuffer header = ByteBuffer.allocate(44);
            header.order(ByteOrder.LITTLE_ENDIAN);

            header.putInt(0x46464952); // "RIFF"
            header.putInt((int) totalDataLen);
            header.putInt(0x45564157); // "WAVE"

            header.putInt(0x20746D66); // "fmt "
            header.putInt(16); // PCM format chunk size
            header.putShort((short) 1); // PCM format tag
            header.putShort((short) channels);
            header.putInt(sampleRate);
            header.putInt((int) byteRate);
            header.putShort((short) ((channels * bitsPerSample) / 8));
            header.putShort(bitsPerSample);

            header.putInt(0x61746164); // "data"
            header.putInt((int) totalAudioLen);
            byte[] array = header.array();
            raf.write(array, 0, array.length);
            raf.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void updateWavHeader(File fd) throws IOException {
        RandomAccessFile raf = new RandomAccessFile(fd, "rw");
        raf.seek(4); // Total Length
        raf.write(intToByteArray((int) raf.length() - 8), 0, 4);
        raf.seek(40); // Data Length
        raf.write(intToByteArray((int) raf.length() - 44), 0, 4);
        raf.getFD().sync();
        raf.close();
    }

    public static void savePcmHeader(BufferedOutputStream os, long totalAudioLen, long longSampleRate, int channels, long byteRate) {
        if (os == null) {
            return;
        }
        byte[] header = new byte[HEADER_SIZE];
        long totalDataLen = totalAudioLen + 36;

        // RIFF/WAVE header
        header[0] = 'R';  // RIFF
        header[1] = 'I';
        header[2] = 'F';
        header[3] = 'F';
        header[4] = (byte) (totalDataLen & 0xff);      // Total length of file - 8
        header[5] = (byte) ((totalDataLen >> 8) & 0xff);
        header[6] = (byte) ((totalDataLen >> 16) & 0xff);
        header[7] = (byte) ((totalDataLen >> 24) & 0xff);
        header[8] = 'W';  // WAVE
        header[9] = 'A';
        header[10] = 'V';
        header[11] = 'E';

        // fmt sub-chunk
        header[12] = 'f';  // fmt
        header[13] = 'm';
        header[14] = 't';
        header[15] = ' ';
        header[16] = 16;   // Subchunk1Size (size of the fmt chunk)
        header[17] = 0;
        header[18] = 0;
        header[19] = 0;
        header[20] = 1;    // AudioFormat (1 for PCM)
        header[21] = 0;
        header[22] = (byte) channels; // NumChannels
        header[23] = 0;
        header[24] = (byte) (longSampleRate & 0xff);   // SampleRate
        header[25] = (byte) ((longSampleRate >> 8) & 0xff);
        header[26] = (byte) ((longSampleRate >> 16) & 0xff);
        header[27] = (byte) ((longSampleRate >> 24) & 0xff);
        header[28] = (byte) (byteRate & 0xff);         // ByteRate
        header[29] = (byte) ((byteRate >> 8) & 0xff);
        header[30] = (byte) ((byteRate >> 16) & 0xff);
        header[31] = (byte) ((byteRate >> 24) & 0xff);
        header[32] = (byte) (channels * 16 / 8);       // BlockAlign
        header[33] = 0;
        header[34] = 16;   // BitsPerSample
        header[35] = 0;

        // data sub-chunk
        header[36] = 'd';  // data
        header[37] = 'a';
        header[38] = 't';
        header[39] = 'a';
        header[40] = (byte) (totalAudioLen & 0xff);    // Subchunk2Size (data size)
        header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
        header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
        header[43] = (byte) ((totalAudioLen >> 24) & 0xff);

        try {
            os.write(header, 0, HEADER_SIZE);
        } catch (IOException e) {
            HLog.isMRLog(e.getMessage());
        }
//        os.write();
    }

    public static byte[] intToByteArray(int value) {
        return new byte[]{
                (byte) (value >> 24),
                (byte) (value >> 16),
                (byte) (value >> 8),
                (byte) value
        };
    }
}
